#include <linux/lsm_hooks.h>
#include <linux/module.h>
#include <linux/xattr.h>

enum controlled_operation {
    FILE_DENY_ALL = 0x0,
    FILE_EXCUTED  = 0x1,
    FILE_REMOVED  = 0x2,
    FILE_MODIFIED = 0x4,
};

static const char* ex_linx_name = "security.linx.filepermit";
// static const char * ex_linxc_name = "security.linxc.filepermit";

int atoi(char c)
{
    if (c > 'z' || c < '0') {
        return -1;
    }
    return (c - '0');
}

// int (*inode_unlink)(struct inode *dir, struct dentry *dentry);
/*	Check the permission to remove a hard link to a file.
 *	@dir contains the inode structure of parent directory of the file.
 *	@dentry contains the dentry structure for file to be unlinked.
 *	Return 0 if permission is granted.
 */
// ssize_t vfs_getxattr(struct dentry *dentry, const char *name, void *value,
// size_t size)
int linx_inode_unlink(struct inode* dir, struct dentry* dentry)
{
    ssize_t len;
    char    ctl_op;

    // printk("unlink file d_iname:%s,d_parent:%s\n", dentry->d_iname,
    // dentry->d_parent->d_iname);
    len = vfs_getxattr(dentry, ex_linx_name, &ctl_op, 1);
    if (len > 0) {
        printk("vfs_getxattr len:%ld,name:%s, controlled_operation:%d\n", len,
               ex_linx_name, atoi(ctl_op));
    }
    return 0;
}

static struct security_hook_list my_hook_list[] = {
    LSM_HOOK_INIT(inode_unlink, linx_inode_unlink),
};

static int proc_init(void)
{
    security_add_hooks(my_hook_list, ARRAY_SIZE(my_hook_list));
    printk("hook-test init \n");
    return 0;
}

static void proc_cleanup(void)
{
    security_delete_hooks(my_hook_list, ARRAY_SIZE(my_hook_list));
    printk("hook-test uninstall \n");
}

module_init(proc_init);
module_exit(proc_cleanup);
MODULE_LICENSE("GPL");
